﻿using System;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Data;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data.SqlClient;

namespace ErpServer
{
    public class Client
    {
        #region  数据成员

        /// <summary>
        /// 与单个客户端进行通讯的线程
        /// </summary>
        private Thread clientThread;
        public Thread ClientThread
        {
            get { return clientThread; }
            set { clientThread = value; }
        }

        /// <summary>
        /// 储存远程客户端的登录名
        /// </summary>
        private string userName;
        public string UserName
        {
            get { return userName; }
            set { userName = value; }
        }

        /// <summary>
        /// 管理员权限等级
        /// </summary>
        private int adminLevel;
        public int AdminLevel
        {
            get { return adminLevel; }
            set { adminLevel = value; }
        }

        /// <summary>
        /// 与远程客户端连接的Socket
        /// </summary>
        private Socket workSock;
        public Socket WorkSock
        {
            get { return workSock; }
            set { workSock = value; }
        }

        /// <summary>
        /// 定义主窗体中显示文本的事件
        /// </summary>
        public static event ShowTextCallback ShowText;

        /// <summary>
        /// 定义显示连接信息的事件
        /// </summary>
        public static event BindCallback Bind;

        /// <summary>
        /// 定义写入日志文件的事件
        /// </summary>
        public static event WriteLogCallback WriteLog;

        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="s">Socket</param>
        /// <param name="userName">登录名</param>
        /// <param name="level">权限等级</param>
        public Client(Socket s, string userName, int level)
        {
            workSock = s;
            this.userName = userName;
            this.adminLevel = level;
            clientThread = new Thread(new ThreadStart(Read));
        }

        /// <summary>
        /// 读取客户端发送来的数据并处理
        /// </summary>
        private void Read()
        {
            byte[] data = new byte[4096];     //存储每次从缓冲区读到的数据
            int bytesRead = 0;                //从缓冲区读到的数据长度
            byte[] packet = null;             //存储整个完整数据的数组
            long packetLength = 0;            //整个完整数据的长度
            long receiveLength = 0;           //当前已接收到的数据长度

            try
            {
                while (true)
                {
                    packetLength = 0;
                    if (bytesRead == 0)
                    {
                        bytesRead = workSock.Receive(data);         //从缓冲区读取数据到data数组

                        for (int i = 0; i < 8; i++)
                        {
                            packetLength += ((long)data[i]) << (i * 8);
                        }
                        packet = new byte[packetLength];
                        for (int i = 0; i < bytesRead - 8; i++)
                        {
                            data[i] = data[i + 8];
                        }
                        bytesRead -= 8;
                    }
                    else
                    {
                        if (bytesRead < 8)
                        {
                            bytesRead = 0;
                            continue;
                        }
                        for (int i = 0; i < 8; i++)
                        {
                            packetLength += ((long)data[i]) << (i * 8);
                        }
                        packet = new byte[packetLength];
                        for (int i = 0; i < bytesRead - 8; i++)
                        {
                            data[i] = data[i + 8];
                        }
                        bytesRead -= 8;
                    }

                    while (packetLength > receiveLength + bytesRead)
                    {
                        for (int i = 0; i < bytesRead; i++)
                        {
                            packet[receiveLength + i] = data[i];
                        }
                        receiveLength += bytesRead;
                        bytesRead = workSock.Receive(data);
                    }
                    if (packetLength == receiveLength + bytesRead)
                    {
                        for (int i = 0; i < bytesRead; i++)
                        {
                            packet[receiveLength + i] = data[i];
                        }
                        solve(packet);
                        bytesRead = 0;
                        receiveLength = 0;
                        packet = null;
                    }
                    else if (packetLength < receiveLength + bytesRead)
                    {
                        int j = 0;
                        for (long i = receiveLength; i < packetLength; i++, j++)
                        {
                            packet[i] = data[j];
                        }
                        bytesRead = bytesRead - j;
                        for (int i = 0; i < bytesRead; i++)
                        {
                            data[i] = data[i + j];
                        }
                        solve(packet);
                        receiveLength = 0;
                        packet = null;
                    }
                }

            }
            catch (SocketException)
            {
                ShowText(userName + "正常下线了\r\n");
                ListenConnection.remove(userName);
                Bind();
                return;
            }
            catch (SqlException)
            {
                Read();
            }
            catch (IndexOutOfRangeException)
            {
                ShowText(userName + "正常下线了\r\n");
                ListenConnection.remove(userName);
                Bind();
                return;
            }
        }

        private void solve(byte[] packet)
        {
            string number = Encoding.ASCII.GetString(packet, 0, 4);
            string str;
            string[] s;
            switch (number)
            {
                case "1010":      //处理修改密码请求
                    str = Encoding.Unicode.GetString(packet, 4, packet.Length - 4);
                    str = DES.DecryptDES(str, "12345678");
                    s = str.Split('|');
                    if (UserLogin.LoginCheck(userName, s[0]) == true)
                    {
                        DBConnection db0 = new DBConnection();
                        int nn = db0.ExecuteSql("update tb_Admin set Password='" + s[1] + "' where AdminName=" + userName);
                        if (nn > 0) Send("1011", "");
                        else Send("1012", "");
                    }
                    else Send("1013", "");
                    break;
                case "1040":      //返回用户指定的DataSet
                    str = Encoding.Unicode.GetString(packet, 4, packet.Length - 4);
                    str = DES.DecryptDES(str, "12345678");
                    DBConnection db1 = new DBConnection();
                    DataSet ds = db1.GetDataSet(str);
                    Send(ds);
                    Bind();
                    break;
                case "1050":      //返回用户指定的DataTable
                    str = Encoding.Unicode.GetString(packet, 4, packet.Length - 4);
                    str = DES.DecryptDES(str, "12345678");
                    DBConnection db4 = new DBConnection();
                    DataTable dt = db4.GetDataTable(str);
                    Send(dt);
                    break;
                case "1060":     //执行SQL语句并返回受影响的行数
                    str = Encoding.Unicode.GetString(packet, 4, packet.Length - 4);
                    str = DES.DecryptDES(str, "12345678");
                    DBConnection db5 = new DBConnection();
                    int affectRows = db5.ExecuteSql(str);
                    Send("1061", affectRows.ToString());
                    Bind();
                    break;
                case "1070":    //返回用户指定的单条记录
                    str = Encoding.Unicode.GetString(packet, 4, packet.Length - 4);
                    str = DES.DecryptDES(str, "12345678");
                    DBConnection db2 = new DBConnection();
                    string[] oneCord = db2.GetStrings(str);
                    Send(oneCord);
                    Bind();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 发送字符串
        /// </summary>
        /// <param name="number">数据类型代码 </param>
        /// <param name="str">字符串</param>
        public void Send(string number, string str)
        {
            ShowText("To " + workSock.RemoteEndPoint + ": " + number + "---" + str + "\r\n");
            str = DES.EncryptDES(str, "12345678");
            byte[] data = Encoding.Unicode.GetBytes(str);
            byte[] send_data = new byte[data.Length + 12];
            byte[] send_num = Encoding.ASCII.GetBytes(number);
            long send_length = (long)data.Length + 4;
            for (int i = 0; i < 8; i++)
            {
                send_data[i] = (byte)(send_length % 256);
                send_length = send_length >> 8;
            }
            for (int i = 0; i < 4; i++)
            {
                send_data[i + 8] = send_num[i];
            }
            for (int i = 0; i < data.Length; i++)
            {
                send_data[i + 12] = data[i];
            }
            workSock.Send(send_data);
        }

        /// <summary>
        /// 发送字符串数组
        /// </summary>
        /// <param name="s">字符串数组</param>
        private void Send(string[] s)
        {
            string str = "";
            if (s == null)
            {
                Send("1071", "");
                return;
            }
            for (int i = 0; i < s.Length - 1; i++)
            {
                str += (s[i] + "|");
            }
            str += s[s.Length - 1];
            Send("1071", str);
        }

        /// <summary>
        /// 发送DataSet
        /// </summary>
        /// <param name="ds">DataSet</param>
        private void Send(DataSet ds)
        {
            byte[] b = ObjectToByteArray((object)ds);
            char[] c = new char[b.Length];
            for (int i = 0; i < b.Length; i++)
                c[i] = (char)b[i];
            string str = new string(c);
            Send("1041", str);
        }

        /// <summary>
        /// 发送DataTable
        /// </summary>
        /// <param name="dt">DataTable</param>
        private void Send(DataTable dt)
        {
            byte[] b = ObjectToByteArray((object)dt);
            char[] c = new char[b.Length];
            for (int i = 0; i < b.Length; i++)
                c[i] = (char)b[i];
            string str = new string(c);
            Send("1051", str);
        }

        /// <summary>
        /// 将可序列化对象转成Byte数组
        /// </summary>
        /// <param name="o">对象</param>
        /// <returns>返回相关数组</returns>
        private byte[] ObjectToByteArray(object o)
        {
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, o);
            ms.Close();
            return ms.ToArray();
        }
    }
}
